--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commit 6db7ea7fe04e5566327c93903b88c3c43499c84c
Parents : e7339cb
Author : Mark Qvist <mark@unsigned.io>
Date : 2021-05-13T16:38:59+02:00
Conversation service basic functionality implemented
Changes
Diff
diff --git a/nomadnet/Conversation.py b/nomadnet/Conversation.py
index 20bcdde..868eb1f 100644
--- a/nomadnet/Conversation.py
+++ b/nomadnet/Conversation.py
@@ -1,48 +1,147 @@
import os
import RNS
import LXMF
+import shutil
+from nomadnet.Directory import DirectoryEntry
class Conversation:
+ cached_conversations = {}
+ created_callback = None
+
@staticmethod
- def ingest(lxmessage, app):
- source_hash_path = RNS.hexrep(lxmessage.source_hash, delimit=False)
+ def ingest(lxmessage, app, originator = False, delegate = None):
+ if originator:
+ source_hash = lxmessage.destination_hash
+ else:
+ source_hash = lxmessage.source_hash
+
+ source_hash_path = RNS.hexrep(source_hash, delimit=False)
+
conversation_path = app.conversationpath + "/" + source_hash_path
if not os.path.isdir(conversation_path):
os.makedirs(conversation_path)
+ if Conversation.created_callback != None:
+ Conversation.created_callback()
+
+ ingested_path = lxmessage.write_to_directory(conversation_path)
+
+ if RNS.hexrep(source_hash, delimit=False) in Conversation.cached_conversations:
+ conversation = Conversation.cached_conversations[RNS.hexrep(source_hash, delimit=False)]
+ conversation.scan_storage()
- lxmessage.write_to_directory(conversation_path)
+ return ingested_path
@staticmethod
def conversation_list(app):
conversations = []
- for entry in os.listdir(app.conversationpath):
- if len(entry) == RNS.Identity.TRUNCATED_HASHLENGTH//8*2 and os.path.isdir(app.conversationpath + "/" + entry):
+ for dirname in os.listdir(app.conversationpath):
+ if len(dirname) == RNS.Identity.TRUNCATED_HASHLENGTH//8*2 and os.path.isdir(app.conversationpath + "/" + dirname):
try:
+ source_hash_text = dirname
+ source_hash = bytes.fromhex(dirname)
+ app_data = RNS.Identity.recall_app_data(source_hash)
+ display_name = app.directory.display_name(source_hash)
+
+ if display_name == None and app_data:
+ display_name = app_data.decode("utf-8")
+
+ trust_level = app.directory.trust_level(source_hash, display_name)
+
+ entry = (source_hash_text, display_name, trust_level)
conversations.append(entry)
+
except Exception as e:
- RNS.log("Error while loading conversation "+str(entry)+", skipping it. The contained exception was: "+str(e), RNS.LOG_ERROR)
+ RNS.log("Error while loading conversation "+str(dirname)+", skipping it. The contained exception was: "+str(e), RNS.LOG_ERROR)
+
+ conversations.sort(key=lambda e: (-e[2], e[1], e[0]), reverse=False)
return conversations
+ @staticmethod
+ def cache_conversation(conversation):
+ Conversation.cached_conversations[conversation.source_hash] = conversation
+ @staticmethod
+ def delete_conversation(source_hash_path, app):
+ conversation_path = app.conversationpath + "/" + source_hash_path
+
+ try:
+ if os.path.isdir(conversation_path):
+ shutil.rmtree(conversation_path)
+ except Exception as e:
+ RNS.log("Could not remove conversation at "+str(conversation_path)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
def __init__(self, source_hash, app):
+ self.app = app
self.source_hash = source_hash
+ self.send_destination = None
+ self.messages = []
self.messages_path = app.conversationpath + "/" + source_hash
self.messages_load_time = None
- self.messages = []
self.source_known = False
self.source_trusted = False
self.source_blocked = False
+ self.__changed_callback = None
+
+ self.source_identity = RNS.Identity.recall(bytes.fromhex(self.source_hash))
+
+ if self.source_identity:
+ self.source_known = True
+ self.send_destination = RNS.Destination(self.source_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "lxmf", "delivery")
+
+ self.scan_storage()
+
+ self.trust_level = app.directory.trust_level(bytes.fromhex(self.source_hash))
+
+ Conversation.cache_conversation(self)
+
+ def scan_storage(self):
+ old_len = len(self.messages)
+ self.messages = []
for filename in os.listdir(self.messages_path):
if len(filename) == RNS.Identity.HASHLENGTH//8*2:
message_path = self.messages_path + "/" + filename
self.messages.append(ConversationMessage(message_path))
+ if self.__changed_callback != None:
+ self.__changed_callback(self)
+
+
def __str__(self):
- return self.source_hash
+ string = self.source_hash
+
+ if self.source_identity:
+ if self.source_identity.app_data:
+ # TODO: Sanitise for viewing
+ string += " | "+self.source.source_identity.app_data.decode("utf-8")
+
+ return string
+
+ def register_changed_callback(self, callback):
+ self.__changed_callback = callback
+
+ def send(self, content="", title=""):
+ if self.send_destination:
+ dest = self.send_destination
+ source = self.app.lxmf_destination
+ lxm = LXMF.LXMessage(dest, source, content, desired_method=LXMF.LXMessage.DIRECT)
+ lxm.register_delivery_callback(self.message_delivered)
+ self.app.message_router.handle_outbound(lxm)
+
+ message_path = Conversation.ingest(lxm, self.app, originator=True)
+ self.messages.append(ConversationMessage(message_path))
+
+ else:
+ # TODO: Implement
+ # Alter UI so message cannot be sent until there is a path, or LXMF propagation is implemented
+ RNS.log("Destination unknown")
+
+ def message_delivered(self, message):
+ message_path = Conversation.ingest(message, self.app, originator=True)
+
+
class ConversationMessage:
def __init__(self, file_path):
@@ -63,6 +162,12 @@ class ConversationMessage:
self.loaded = False
self.lxm = None
+ def get_timestamp(self):
+ if not self.loaded:
+ self.load()
+
+ return self.timestamp
+
def get_title(self):
if not self.loaded:
self.load()
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────